import re
from datetime import datetime
from typing import List, Any

from django.conf import settings
# from users.models import User
from django.contrib.auth import get_user_model
from django.shortcuts import get_object_or_404
from django_redis import get_redis_connection
from itsdangerous import URLSafeTimedSerializer as URLSTS
from ninja import Router
from ninja_extra.exceptions import APIException
from ninja_extra.permissions import IsAuthenticated
from ninja_jwt.authentication import JWTAuth
from ninja_jwt.tokens import SlidingToken

from goods.models import SKU
from goods.schema import SKUSchemaOut
from meiduo_mall.base.schemas import Message
from users.schemas import UserSchemaOut, UserSchemaIn, UserUpdateSchema, UserTokenOutSchema, AddressSchemaOut, \
    AddressesSchemaOut, AddressSchemaIn, UserBrowseHistorySchemaIn  # 正确导包
from .models import Address

# from django.contrib.auth import authenticate

User = get_user_model()

api = Router(tags=['注册校验'])


# ————————————————————————FBV方式———————————————————————— #
@api.post('', response=UserTokenOutSchema, summary='用户注册')
def add_user(request, data: UserSchemaIn):
    """用户注册，注册成功返回TOKEN"""
    # user = User.objects.create(**data.dict()) UserSchemaIn没有自定义字段内容时用此代码新建对象

    user = User(username=data.username, mobile=data.mobile)
    user.set_password(data.password2)
    user.save()

    # 用户注册成功直接跳转首页，不做重登录
    # 生成令牌
    token = SlidingToken.for_user(user)
    return UserTokenOutSchema(
        user=user,
        token=str(token),
        token_exp_date=datetime.fromtimestamp(token["exp"]),
    )


# 注册校验用户名和手机号是否已注册 -- 基于类的方法
# ————————————————————————CBV方式———————————————————————— #
from ninja_extra import route, api_controller


@api_controller(tags=['注册校验'])
class ValidateUserInfo:
    @route.get('unique/mobile/{mobile}/', summary="校验手机号", url_name="unique-mobile", description='校验手机号是否已注册')
    def unique_mobile(self, mobile: int):
        mobiles = mobile if re.match(r'1[3-9]\d{9}', str(mobile)) else ''
        count = User.objects.filter(mobile=mobile).count()
        data = {
            'mobile': mobiles,
            'count': count
        }
        return data

    @route.get('unique/username/{username}/', summary="校验用户名", url_name="unique-username", )
    def unique_username(self, username):
        """校验用户名是否已注册"""
        count = User.objects.filter(username=username).count()
        data = {
            'username': username,
            'count': count
        }
        return data


@api_controller(tags=['用户信息'], auth=JWTAuth())
class UserInfoController:
    @route.get('/users/', response={200: List[UserSchemaOut], 400: Message}, summary='查看所有用户')
    def get_users(self):
        """查看所有用户详细信息"""
        qs = User.objects.all()
        return 200, qs

    @route.get('user/{uid}', response={200: UserSchemaOut, 400: Message}, summary='用户详情')
    def get_user(self, uid: int):
        """查看指定用户详细信息"""
        user = User.objects.filter(id=uid)
        if not user:
            return 400, {'msg': '用户不存在'}
        return 200, user
        # return get_object_or_404(User, id=uid, )


@api_controller(tags=['个人中心'])
class UserCenter:
    @route.get('/userinfo/', response={200: UserTokenOutSchema, 401: Message}, summary='个人中心',
               permissions=[IsAuthenticated, ], url_name='userinfo', auth=JWTAuth())
    def user_center(self):
        """个人详细信息"""
        # if self.context.request.user.email_active is False:
        #     return 401, {'msg': '邮箱未激活'}
        token = SlidingToken.for_user(self.context.request.user)
        return 200, UserTokenOutSchema(
            user=self.context.request.user,
            token=str(token),
            token_exp_date=datetime.fromtimestamp(token["exp"]),
        )

    @route.put('/userinfo/', response={200: Message, 422: Message}, summary='更新邮箱',
               permissions=[IsAuthenticated, ], auth=JWTAuth())
    def update_email(self, data: UserUpdateSchema):
        """"""
        user = self.context.request.user
        # for v, k in data.dict().items():
        #     setattr(user, v, k)
        # user.save()
        data.update(user)
        # ⽣生成激活链接
        verify_url = settings.CORS_ORIGIN_WHITELIST[0] + '/success_verify_email.html' + user.generate_verify_url()
        print(verify_url)
        # 异步发送邮件
        from celery_tasks.email.tasks import send_verify_email
        send_verify_email.delay(user.email, verify_url)
        return 200, {'msg': 'ok'}

    @route.get('/verify_email', response={200: Message, 422: Message}, summary='激活邮箱', url_name='verify_email', )
    def verify_email(self):
        token = self.context.request.GET.get('token')
        serializer = URLSTS(settings.SECRET_KEY, salt=settings.SECRET_KEY)
        expiration = 1000  # 邮件过期时间,方便调整，暂时放在这里
        try:
            data = serializer.loads(token, max_age=expiration)
        except:
            raise APIException('激活邮件已过期，请重新发送')
        user = get_object_or_404(User, **data)
        if user.email_active:
            return 200, {'msg': '邮箱已经激活，无需再次激活'}
        user.email_active = True
        user.save()
        return 200, {'msg': '邮箱已激活'}


@api_controller(tags=['收货地址'], auth=JWTAuth(), permissions=[IsAuthenticated])
class AddressAPI:
    @route.get('addresses/', summary='查看收货地址', response={200: Any, 401: Message})
    def addresses(self):
        try:
            user = self.context.request.user
            # qs = Address.objects.filter(user=self.context.request.user)
            qs = user.addresses.filter(is_deleted=False)
            return 200, AddressesSchemaOut(
                user_id=user.id,
                default_address_id=user.default_address_id,
                limit=20,
                addresses=qs,
            )
        except Exception as e:
            print(e)
            return 401, {'msg': '服务器错误，请重试'}

    @route.post('/addresses/', summary='添加收货地址', response={200: AddressSchemaOut, 400: Message})
    def add_address(self, data: AddressSchemaIn):
        user = self.context.request.user
        if user.addresses.all().count() >= 20:
            return 400, {'msg': "收货地址已达上限"}
        try:
            obj = Address.objects.create(user=user, **data.dict())
        except ValueError as e:
            return 400, {'msg': f"{e}"}
        return 200, obj

    @route.delete('/addresses/{id}/', summary='删除收货地址', response={200: Message, 400: Message})
    def delete_addr(self, id: int):
        try:
            # 删除地址的ID
            address = get_object_or_404(Address, id=id)
        except:
            return 400, {'msg': '地址不存在，请刷新后重试'}
        # 逻辑删除
        address.is_deleted = True
        address.save()
        # 响应
        return 200, {'msg': 'ok'}

    @route.put('/addresses/{id}/title/', summary='更新收货地址', response={200: Message, 400: Message})
    def put_addr(self, id: int, data: AddressSchemaIn):
        try:
            address = get_object_or_404(Address, id=id)
            for k, v in data.dict().items():
                if v != None:  # 非空约束的字段忽略
                    setattr(address, k, v)
            address.save()
            return 200, {'msg': 'ok'}
        except:
            return 400, {'msg': '地址不存在，请刷新'}

    @route.put('/addresses/{id}/status/', summary='设置默认地址', response={200: Message, 400: Message})
    def put_default_addr(self, id: int):
        try:
            address = get_object_or_404(Address, id=id)
        except:
            return 400, {'msg': '地址不存在，请刷新'}
        self.context.request.user.default_address_id = address.id
        self.context.request.user.save()
        return 200, {'msg': 'ok'}


@api_controller(tags=['个人中心'], permissions=[IsAuthenticated], auth=JWTAuth())  #
class UserBrowseHistory:
    @route.post('browse_histories/', summary='添加浏览记录', response={200: Message, 400: Message})
    def post_browse_histories(self, data: UserBrowseHistorySchemaIn):
        return {'msg': 'ok'}

    @route.get('browse_histories/', summary='查看浏览记录', response={200: List[SKUSchemaOut], 400: Message})
    def get_browse_histories(self):
        redis_conn = get_redis_connection('history')
        sku_ids = redis_conn.lrange(f'history_{self.context.request.user.id}', 0, -1)
        sku_list = []
        for sku_id in sku_ids:
            sku = SKU.objects.get(id=sku_id)
            sku_list.append(sku)
        return sku_list


"""
exclude_unset
在创建模式时未设置且具有默认值的字段是否从响应中排除（默认为 False）。

exclude_defaults
设置了默认值的字段是否从响应schema中排除（默认为 False）。

exclude_none
等于 None 的字段是否从响应中排除（默认为 False）。

"""
